Support glob syntax in workspace members
authorHerman J. Radtke III <herman@hermanradtke.com>
Sat, 29 Apr 2017 02:08:07 +0000 (19:08 -0700)
committerHerman J. Radtke III <herman@hermanradtke.com>
Sat, 29 Apr 2017 18:24:17 +0000 (11:24 -0700)
Fixes #3911

src/cargo/core/workspace.rs
tests/workspaces.rs

index 5015448a569cef6494b82825e2ef72fa836ab076..0054586c945c892dbfcae4be5b85fe815a5bbe85 100644 (file)
@@ -3,6 +3,8 @@ use std::collections::BTreeMap;
 use std::path::{Path, PathBuf};
 use std::slice;
 
+use glob::glob;
+
 use core::{Package, VirtualManifest, EitherManifest, SourceId};
 use core::{PackageIdSpec, Dependency, Profile, Profiles};
 use ops;
@@ -316,9 +318,16 @@ impl<'cfg> Workspace<'cfg> {
         };
 
         if let Some(list) = members {
+            let root = root_manifest.parent().unwrap();
+
+            let mut expanded_list = Vec::new();
             for path in list {
-                let root = root_manifest.parent().unwrap();
-                let manifest_path = root.join(path).join("Cargo.toml");
+                let expanded_paths = expand_member_path(&path, root)?;
+                expanded_list.extend(expanded_paths);
+            }
+
+            for path in expanded_list {
+                let manifest_path = path.join("Cargo.toml");
                 self.find_path_deps(&manifest_path, &root_manifest, false)?;
             }
         }
@@ -527,6 +536,19 @@ impl<'cfg> Workspace<'cfg> {
     }
 }
 
+fn expand_member_path(member_path: &str, root_path: &Path) -> CargoResult<Vec<PathBuf>> {
+    let path = root_path.join(member_path);
+    let path = path.to_str().unwrap();
+    let res = glob(path).map_err(|e| {
+        human(format!("could not parse pattern `{}`: {}", &path, e))
+    })?;
+    res.map(|p| {
+        p.or_else(|e| {
+            Err(human(format!("unable to match path to pattern `{}`: {}", &path, e)))
+        })
+    }).collect()
+}
+
 fn is_excluded(members: &Option<Vec<String>>,
                exclude: &[String],
                root_path: &Path,
index 7df7bf8da3f9bf67d7212b2b9e42579156bb7d73..a47c6074ae6a141da1c05bd05cbd27f5042e701b 100644 (file)
@@ -1378,3 +1378,67 @@ fn exclude_but_also_depend() {
                 execs().with_status(0));
     assert_that(&p.root().join("foo/bar/target"), existing_dir());
 }
+
+#[test]
+fn glob_syntax() {
+    let p = project("foo")
+        .file("Cargo.toml", r#"
+            [project]
+            name = "foo"
+            version = "0.1.0"
+            authors = []
+
+            [workspace]
+            members = ["crates/*"]
+            exclude = ["crates/qux"]
+        "#)
+        .file("src/main.rs", "fn main() {}")
+        .file("crates/bar/Cargo.toml", r#"
+            [project]
+            name = "bar"
+            version = "0.1.0"
+            authors = []
+            workspace = "../.."
+        "#)
+        .file("crates/bar/src/main.rs", "fn main() {}")
+        .file("crates/baz/Cargo.toml", r#"
+            [project]
+            name = "baz"
+            version = "0.1.0"
+            authors = []
+            workspace = "../.."
+        "#)
+        .file("crates/baz/src/main.rs", "fn main() {}")
+        .file("crates/qux/Cargo.toml", r#"
+            [project]
+            name = "qux"
+            version = "0.1.0"
+            authors = []
+        "#)
+        .file("crates/qux/src/main.rs", "fn main() {}");
+    p.build();
+
+    assert_that(p.cargo("build"), execs().with_status(0));
+    assert_that(&p.bin("foo"), existing_file());
+    assert_that(&p.bin("bar"), is_not(existing_file()));
+    assert_that(&p.bin("baz"), is_not(existing_file()));
+
+    assert_that(p.cargo("build").cwd(p.root().join("crates/bar")),
+                execs().with_status(0));
+    assert_that(&p.bin("foo"), existing_file());
+    assert_that(&p.bin("bar"), existing_file());
+
+    assert_that(p.cargo("build").cwd(p.root().join("crates/baz")),
+                execs().with_status(0));
+    assert_that(&p.bin("foo"), existing_file());
+    assert_that(&p.bin("baz"), existing_file());
+
+    assert_that(p.cargo("build").cwd(p.root().join("crates/qux")),
+                execs().with_status(0));
+    assert_that(&p.bin("qux"), is_not(existing_file()));
+
+    assert_that(&p.root().join("Cargo.lock"), existing_file());
+    assert_that(&p.root().join("crates/bar/Cargo.lock"), is_not(existing_file()));
+    assert_that(&p.root().join("crates/baz/Cargo.lock"), is_not(existing_file()));
+    assert_that(&p.root().join("crates/qux/Cargo.lock"), existing_file());
+}